package 多线程的同步互斥实验数组;

import java.util.ArrayList;
import java.util.List;

/*思路:
 * 1.首先加入同步锁synchronized
 * 2.假如消费者1先执行,这时候count为0,进入wait阶段(利用while等待),wait释放锁，并且等待执行，这时候了下一个线程执行
 * 3.假如下一个线程是消费者2，这时候count依然为0,进入wait阶段,也在等待执行，下一个进程执行
 * 4.假如下一个线程是消费者3，这时候count为0，进入wait阶段，也等待执行，下一个进程执行
 * 5.假如下一个线程是生产者，之后将这个food加入room存放，此时放在room[0]的位置
 * 6.这时候执行输出语句，因为productThread在for循环中new Food(1)，所以输出生产第食物编号1,然后将count++,用于计算有多少个产品了
 * 7.之后执行nofityAll()唤醒所有线程，之后进入下一个线程(notify方法只唤醒一个等待（对象的）线程并使该线程开始执行。所以如果有多个线程等待一个对象
 * 这个方法只会唤醒其中一个线程，选择哪个线程取决于操作系统对多线程管理的实现。notifyAll 会唤醒所有等待(对象的)线程，尽管哪一个线程将会第一个处理
 * 取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒，推荐使用notifyAll 方法。)
 * 8.假如下一个线程是消费者1，count不为0，执行while后面的语句
 * 9.首先将count--，目的是从room中移除添加的数据，由于room从0计数,所以要先将为1的count--，之后remove(count),即移除最后添加的一条数据
 * 10.再利用Food food=room.remove(count)拿到被移除的数据，此时的food是被移除的那条数据
 * 11.之后再输出food的信息，然后执行nofityall()唤醒所有等待的线程，之后进入下一条线程
 * 12.继续执行，如上
 * */
public class ProductConsume<Food> {
    public static final int Max = 10;  //最大值
    public static int count = 0;
    public List<Food> room = new ArrayList<Food>(Max);//用于存food,当一个food被卖出后，直接remove掉，防止其他消费者线程重复消费

    public synchronized void produce(Food food) throws InterruptedException {
        while (count >= Max) {
            System.out.println("数量爆满，等待消费者消费。。。");
            this.wait();
        }
        room.add(food);
        //System.out.println(Thread.currentThread().getName()+"生产第>>"+food.toString());//单生产者多消费者
        System.out.println(Thread.currentThread().getName() + "合计>>" + room.size());//多生产者多消费者
        count++;
        notifyAll(); //唤醒在此对象监视器上等待的线程
    }

    public synchronized Food consume() throws InterruptedException {
        while (count <= 0) {
            System.out.println("数量不足，等待生产者生产。。。");
            this.wait();
        }
        count--;                                       //先减去count是因为list从0开始，即删除最后一个添加的数据
        Food food = room.remove(count);                 //返回的是删除的那个对象
        //System.out.println(Thread.currentThread().getName()+"消费第>>"+food.toString());//单生产者多消费者
        System.out.println(Thread.currentThread().getName() + "合计>>" + room.size());//多生产者多消费者

        notifyAll();
        return food;
    }
}
